package com.pz.gulimall.auth.service;

import com.alibaba.druid.util.StringUtils;
import com.pz.gulimall.auth.feign.OrderFeign;
import com.pz.gulimall.auth.feign.ProductFeign;
import com.pz.gulimall.auth.feign.WareFeign;
import com.pz.gulimall.common.exception.BizCodeEnum;
import com.pz.gulimall.common.exception.RRException;
import com.pz.gulimall.common.to.OrderInfoTo;
import com.pz.gulimall.common.to.SkuHasStockTo;
import com.pz.gulimall.common.to.SkuInfoTo;
import com.pz.gulimall.common.to.SkuSaleAttrTo;
import com.pz.gulimall.common.utils.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisKeyValueTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Service
public class OrderService {
    @Autowired
    private OrderFeign orderFeign;
    @Autowired
    private ProductFeign productFeign;
    @Autowired
    private WareFeign wareFeign;
    @Autowired
    private ThreadPoolExecutor executor;
    @Autowired
    private StringRedisTemplate redisTemplate;
    private static final String orderTokenPrefix = "OrderToKen-";

    public R saveOrder(OrderInfoTo orderInfoTo) {
        // 验证请求token，防止重复提交订单
        String key = orderTokenPrefix+orderInfoTo.getOrderToken();
        String orderTokenCache = redisTemplate.opsForValue().get(key);
        if(StringUtils.isEmpty(orderTokenCache)){
            redisTemplate.opsForValue().set(key, orderInfoTo.getOrderToken(), 5, TimeUnit.MINUTES);
        } else {
            return R.error("请勿重复提交订单");
        }
        try {
            R r = orderFeign.saveOrder(orderInfoTo);
            if(r.getCode() == 0){
                return R.ok().put("data", r.get("data"));
            } else {
                return R.error(r.getCode(), r.getMsg()).put("data", r.get("data"));
            }
        } catch (Exception e) {
            throw new RRException(BizCodeEnum.AUTH_RPC_ORDER_FAILED);
        }

    }

    public R getOrders(Map<String, Object> params) {
        try {
            R ans = orderFeign.list(params);
            return R.ok().put("data", ans.get("page"));
        } catch (Exception e) {
            throw new RRException(BizCodeEnum.AUTH_RPC_ORDER_FAILED, e.getMessage());
        }
    }

    public R getProducts(List<Long> skuIds) {
        //获取sku基本信息
        CompletableFuture<List<SkuInfoTo>> task1 = CompletableFuture.supplyAsync(() -> {
            try {
                R ans = productFeign.getByIds(skuIds);
                if (ans.getCode() == 0) {
                    return ans.getDataArray(SkuInfoTo.class);
                } else {
                    throw new RRException(ans);
                }
            } catch (Exception e) {
                throw new RRException(BizCodeEnum.AUTH_RPC_PRODUCT_FAILED, e.getMessage());
            }
        }, executor);

        //获取库存信息
        CompletableFuture<List<SkuHasStockTo>> task2 = CompletableFuture.supplyAsync(() -> {
            try {
                R ans = wareFeign.hasStockBySkuId(skuIds);
                if (ans.getCode() == 0) {
                    return ans.getDataArray(SkuHasStockTo.class);
                } else {
                    throw new RRException(ans);
                }
            } catch (Exception e) {
                throw new RRException(BizCodeEnum.AUTH_RPC_WARE_FAILED, e.getMessage());
            }
        }, executor);

        //获取销售信息
        CompletableFuture<Map<Long, List<String>>> task3 = CompletableFuture.supplyAsync(() -> {
            Map<Long, List<String>> skuIdSaleAttrsMap = new HashMap<>(); //{key: skuId, value: saleAttrs}
            try {
                R ans = productFeign.getSaleAttrBatch(skuIds);
                if (ans.getCode() == 0) {
                    List<SkuSaleAttrTo> dataArray = ans.getDataArray(SkuSaleAttrTo.class);
                    dataArray.forEach(item->{
                        skuIdSaleAttrsMap.put(item.getSkuId(), item.getSaleAttrValues());
                    });
                } else {
                    throw new RRException(ans);
                }
            } catch (Exception e) {
                throw new RRException(BizCodeEnum.AUTH_RPC_PRODUCT_FAILED, e.getMessage());
            }
            return skuIdSaleAttrsMap;
        }, executor);

        CompletableFuture<List<SkuInfoTo>> task4 = task1.thenCombineAsync(task2, (res1, res2) -> {
            Map<Long, Boolean> hasStockMap = new HashMap<>();
            res2.forEach(item -> {
                hasStockMap.put(item.getSkuId(), item.getHasStock());
            });
            res1.forEach(item -> {
                item.setHasStock(hasStockMap.get(item.getSkuId()));
            });
            return res1;
        }, executor);

        CompletableFuture<List<SkuInfoTo>> task5 = task4.thenCombineAsync(task3, (res1, res3) -> {
            res1.forEach(item -> {
                item.setSaleAttrs(res3.get(item.getSkuId()));
            });
            return res1;
        }, executor);

        try {
            List<SkuInfoTo> skuInfoTos = task5.get();
            return R.ok().put("data", skuInfoTos);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
            throw new RRException(BizCodeEnum.THREAD_EXCEPTION, e.getMessage());
        }

    }

}
